package example.org.word;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import example.org.word.wordUtils.XWPFHelper;
import example.org.word.wordUtils.XWPFHelperTable;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import java.io.IOException;
import java.math.BigInteger;
import java.rmi.server.ExportException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;

public class WordCreator {

    private XWPFDocument document;
    private XWPFHelperTable xwpfHelperTable;
    private XWPFHelper xwpfHelper;
    private static BigInteger abstractNumId = BigInteger.valueOf(0);
    private static Boolean chineseNum = false;

    public WordCreator(String titleName) {
        this.document = new XWPFDocument();
        this.xwpfHelperTable = new XWPFHelperTable();
        this.xwpfHelper = new XWPFHelper();
        createTitle(titleName);
    }


    /**
     * 排序
     */
    private BigInteger createNumbering(){
        XWPFNumbering xwpfNumbering= document.createNumbering();
        XWPFAbstractNum xwpfAbstractNum = null;
        //创建序列号，第一组必定是中文序列号（有且只有一组）（一、二、三、），后面的创建序列号请求全部返回阿拉伯数字序列号（1. 2. 3.）
        if (chineseNum){
            xwpfAbstractNum = createAbstractNum123();
        }else{
            xwpfAbstractNum = createAbstractNumChinese();
        }
        xwpfNumbering.addAbstractNum(xwpfAbstractNum);
        return xwpfNumbering.addNum(xwpfAbstractNum.getAbstractNum().getAbstractNumId());
    }

    private XWPFAbstractNum createAbstractNum123(){
        CTAbstractNum ctAbstractNum = CTAbstractNum.Factory.newInstance();
        ctAbstractNum.setAbstractNumId(abstractNumId);
        abstractNumId = abstractNumId.add(BigInteger.valueOf(1));
        CTLvl ctLvl = ctAbstractNum.addNewLvl();
        ctLvl.addNewLvlText().setVal("%1.");
        ctLvl.addNewLvlJc().setVal(STJc.LEFT);
        ctLvl.addNewNumFmt().setVal(STNumberFormat.DECIMAL);
        //起始数
        CTDecimalNumber ctDecimalNumber = CTDecimalNumber.Factory.newInstance();
        ctDecimalNumber.setVal(BigInteger.valueOf(1));
        ctLvl.setStart(ctDecimalNumber);
        //左边空的距离
        ctLvl.addNewPPr().addNewInd().setLeft(BigInteger.valueOf(420));

        //设置序列样式
        CTRPr ctrPr = ctLvl.addNewRPr();
        CTFonts ctFonts = ctrPr.addNewRFonts();
        ctFonts.setAscii("宋体");
        ctFonts.setHAnsi("宋体");
        ctFonts.setEastAsia("宋体");
        ctFonts.setCs("宋体");

        //加粗
//        ctrPr.addNewB();
//        ctrPr.addNewBCs();

        ctrPr.addNewSz().setVal(BigInteger.valueOf(28));
        ctrPr.addNewSzCs().setVal(BigInteger.valueOf(28));

        XWPFAbstractNum xwpfAbstractNum = new XWPFAbstractNum(ctAbstractNum);
        return xwpfAbstractNum;
    }

    private XWPFAbstractNum createAbstractNumChinese(){
        CTAbstractNum ctAbstractNum = CTAbstractNum.Factory.newInstance();
        ctAbstractNum.setAbstractNumId(abstractNumId);
        abstractNumId = abstractNumId.add(BigInteger.valueOf(1));
        //lvl
        CTLvl ctLvl = ctAbstractNum.addNewLvl();
        ctLvl.addNewLvlText().setVal("%1.");
        ctLvl.addNewLvlJc().setVal(STJc.LEFT);
        ctLvl.addNewNumFmt().setVal(STNumberFormat.CHINESE_COUNTING);
        CTDecimalNumber ctDecimalNumber = CTDecimalNumber.Factory.newInstance();
        ctDecimalNumber.setVal(BigInteger.valueOf(1));
        ctLvl.setStart(ctDecimalNumber);
        //pPr.ind
        CTInd ctInd = ctLvl.addNewPPr().addNewInd();
        ctInd.setLeft(BigInteger.valueOf(0));
//        ctInd.setHanging(BigInteger.valueOf(425));
        //设置序列样式 rPr
        CTRPr ctrPr = ctLvl.addNewRPr();
        CTFonts ctFonts = ctrPr.addNewRFonts();
        ctFonts.setAscii("黑体");
        ctFonts.setHAnsi("黑体");
        ctFonts.setEastAsia("黑体");
        ctFonts.setCs("黑体");
        //加粗
//        ctrPr.addNewB();
//        ctrPr.addNewBCs();
        //设置字体大小
        ctrPr.addNewSz().setVal(BigInteger.valueOf(28));
        ctrPr.addNewSzCs().setVal(BigInteger.valueOf(28));

        XWPFAbstractNum xwpfAbstractNum = new XWPFAbstractNum(ctAbstractNum);
        chineseNum = true;
        return xwpfAbstractNum;
    }

    /**
     * 创建标题
     * @param titleName
     */
    private void createTitle(String titleName) {
        XWPFParagraph titleParagraph = document.createParagraph();    //新建一个标题段落对象（就是一段文字）
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);//样式居中
        XWPFRun titleFun = titleParagraph.createRun();    //创建文本对象
        titleFun.setText(titleName); //设置标题的名字
        titleFun.setBold(true); //加粗
//        titleFun.setColor("000000");//设置颜色
        titleFun.setFontSize(18);    //字体大小
        titleFun.setFontFamily("黑体");//设置字体
        //...
//        titleFun.addBreak();    //换行
    }

    /**
     * 创建标题样式
     * @param jsonObject
     */
    private void createTitleParagraph(JSONObject jsonObject,BigInteger numId) {
        XWPFParagraph titleParagraph = document.createParagraph();    //新建一个标题段落对象（就是一段文字）
        try {
            if (jsonObject.getInteger("abstractNumLvl")>0){
                titleParagraph.setNumID(numId);
            }
        }catch (Exception e){
            //pass
        }
        titleParagraph.setAlignment(ParagraphAlignment.LEFT);//样式居左
        try {
            JSONArray runs = jsonObject.getJSONArray("runs");  //可能为空
            runs.forEach(obj ->{
                JSONObject jo = JSON.parseObject(obj.toString());
                String text = jo.getString("text"); //可能为空
                XWPFRun titleFun = titleParagraph.createRun();    //创建文本对象
                titleFun.setText(text); //设置标题的名字
                try {
                    if (jo.getBoolean("underline")){
                        titleFun.setUnderline(UnderlinePatterns.SINGLE);
                    }
                }catch (Exception e){
                    //pass
                }
//            titleFun.setBold(true); //加粗
//        titleFun.setColor("000000");//设置颜色
                titleFun.setFontSize(14);    //字体大小
                titleFun.setFontFamily("黑体");//设置字体
                //...
//        titleFun.addBreak();    //换行
            });
        }catch (Exception e){
            //pass
        }
    }


    private void createCommonParagraph(JSONObject jsonObject, BigInteger numId) {
        XWPFParagraph CommonParagraph = document.createParagraph();    //新建一个标题段落对象（就是一段文字）
        try {
            if (jsonObject.getInteger("abstractNumLvl")>0){
                CommonParagraph.setNumID(numId);
            }
        }catch (Exception e){
            //pass
        }
        CommonParagraph.setAlignment(ParagraphAlignment.LEFT);//样式居左

        try {
            if (jsonObject.get("firstLine")!=null){
                CommonParagraph.setFirstLineIndent(425);
            }
        }catch (Exception e){
            //pass
        }
        try {
            JSONArray runs = jsonObject.getJSONArray("runs");  //可能为空
            runs.forEach(obj ->{
                JSONObject jo = JSON.parseObject(obj.toString());
                String text = jo.getString("text"); //可能为空，空则跳过
                XWPFRun titleFun = CommonParagraph.createRun();    //创建文本对象
                titleFun.setText(text); //设置标题的名字
                try {
                    if (jo.getBoolean("underline")){
                        titleFun.setUnderline(UnderlinePatterns.SINGLE);
                    }
                }catch (Exception e){
                    //pass
                }
//            titleFun.setBold(true); //加粗
//        titleFun.setColor("000000");//设置颜色
                titleFun.setFontSize(14);    //字体大小
                titleFun.setFontFamily("宋体");//设置字体
                //...
//        titleFun.addBreak();    //换行
            });
        }catch (Exception e){
            //pass
        }
    }

    private void createTip(JSONObject jsonObject, BigInteger numId) {
        XWPFParagraph tipParagraph = document.createParagraph();    //新建一个标题段落对象（就是一段文字）
        tipParagraph.setFirstLineIndent(420); //首行缩进两字符：设置值为（run）fontsize*40 或 ctSize * 20
        try {
            if (jsonObject.getInteger("abstractNumLvl")>0){
                tipParagraph.setNumID(numId);
            }
        }catch (Exception e){
            //pass
        }
        tipParagraph.setAlignment(ParagraphAlignment.LEFT);//样式居左
        try {
            JSONArray runs = jsonObject.getJSONArray("runs");  //可能为空
            runs.forEach(obj ->{
                JSONObject jo = JSON.parseObject(obj.toString());
                String text = jo.getString("text"); //可能为空，空则跳过
                XWPFRun titleFun = tipParagraph.createRun();    //创建文本对象
                titleFun.setText(text); //设置标题的名字
                try {
                    if (jo.getBoolean("underline")){
                        titleFun.setUnderline(UnderlinePatterns.SINGLE);
                    }
                }catch (Exception e){
                    //pass
                }
//            titleFun.setBold(true); //加粗
//        titleFun.setColor("000000");//设置颜色
//                titleFun.setFontSize(21);    //字体大小
                //设置字体，run直接设置时无法设置10.5之类的小数
                CTRPr pr = titleFun.getCTR().getRPr();
                CTHpsMeasure ctSize = pr.isSetSz() ? pr.getSz() : pr.addNewSz();
                ctSize.setVal(BigInteger.valueOf(21));

                titleFun.setFontFamily("宋体");//设置字体
                //...
//        titleFun.addBreak();    //换行
            });
        }catch (Exception e){
            //pass
        }
    }

    /**
     * 设置表格
     */
    private void createTable(JSONObject jsonObject) {
//        Boolean fields = false;
        int rows = jsonObject.getInteger("rows");
        int cols = jsonObject.getInteger("cols");
//        if (jsonObject.get("fields")!=null && jsonObject.get("fieldsList")!=null && jsonObject.getJSONArray("fieldsList").size()>0){
//            rows += jsonObject.getJSONArray("fieldsList").size();
//            fields = true;
//        }
        XWPFTable infoTable = document.createTable(rows, cols);
        infoTable.setWidthType(TableWidthType.DXA);
//        infoTable.setWidthType(TableWidthType.PCT);
//        infoTable.setWidth("88%");
//        infoTable.setTableAlignment(TableRowAlign.CENTER);
        xwpfHelperTable.setTableWidthAndHAlign(infoTable, "8000", STJc.CENTER);

        for (int row = 0; row < rows;row++){
            XWPFTableRow tableRow = infoTable.getRow(row);
            for (int col = 0; col < cols;col++){
                XWPFTableCell tableCell = tableRow.getCell(col);
                tableCell.setWidthType(TableWidthType.DXA);
                Integer w = XWPFHelperTable.defaultWidth/cols;
                tableCell.setWidth(w.toString());
            }
        }

        //设置grid,合并列表用
        CTTblGrid ctTblGrid = CTTblGrid.Factory.newInstance();
        CTTblGridCol[] ctTblGridCols = new CTTblGridCol[cols];
        IntStream.range(0,cols).forEach(i->{
            CTTblGridCol c = CTTblGridCol.Factory.newInstance();
            c.setW(BigInteger.valueOf(XWPFHelperTable.defaultWidth/cols));
            ctTblGridCols[i] = c;
        });
        ctTblGrid.setGridColArray(ctTblGridCols);
        infoTable.getCTTbl().setTblGrid(ctTblGrid);

        //合并表格
        JSONArray merge = jsonObject.getJSONArray("merge");
        merge.forEach(s ->{
            try {
                String str = s.toString();
                String ss[] = str.split("_");
                String from[] = ss[0].split("\\.");
                Integer fromRow = Integer.parseInt(from[0]);
                Integer fromCell = Integer.parseInt(from[1]);
                String to[] = ss[1].split("\\.");
                Integer toRow = Integer.parseInt(to[0]);
                Integer toCell = Integer.parseInt(to[1]);

                xwpfHelperTable.mergeCellsHAV(infoTable, fromRow,fromCell,toRow,toCell);

            }catch (Exception e){
                System.out.println("表格合并格式有误");
                e.printStackTrace();
            }
        });
        //设置表格样式
        List<XWPFTableRow> rowList = infoTable.getRows();
        for(int i = 0; i < rowList.size(); i++) {
            XWPFTableRow infoTableRow = rowList.get(i);
            List<XWPFTableCell> cellList = infoTableRow.getTableCells();
            for(int j = 0; j < cellList.size(); j++) {
                XWPFParagraph cellParagraph = cellList.get(j).getParagraphArray(0);
                cellParagraph.setAlignment(ParagraphAlignment.CENTER);
                XWPFRun cellParagraphRun = cellParagraph.createRun();
                //设置字体，run直接设置时无法设置10.5之类的小数
//                CTRPr pr = cellParagraphRun.getCTR().getRPr();
//                CTHpsMeasure ctSize = pr.isSetSz() ? pr.getSz() : pr.addNewSz();
//                ctSize.setVal(BigInteger.valueOf(28));
                cellParagraphRun.setFontSize(14);

                cellParagraphRun.setFontFamily("宋体");
//                if(i % 2 != 0) cellParagraphRun.setBold(true);
            }
        }
        xwpfHelperTable.setTableHeight(infoTable, 560, STVerticalJc.CENTER);
        JSONArray tableData = jsonObject.getJSONArray("runs");
        fillTableData(infoTable,tableData);
//        if (fields){
//            fillFields(infoTable,tableData.size(),jsonObject.getJSONArray("fields"),jsonObject.getJSONArray("fieldsList"));
//        }
    }

    private void fillTableData(XWPFTable table, JSONArray tableData) {
        List<XWPFTableRow> rowList = table.getRows();
        for(int i = 0; i < tableData.size(); i++) {
            JSONArray list = tableData.getJSONArray(i);
            List<XWPFTableCell> cellList = rowList.get(i).getTableCells();
            for(int j = 0; j < list.size(); j++) {
                XWPFParagraph cellParagraph = cellList.get(j).getParagraphArray(0);
                XWPFRun cellParagraphRun = cellParagraph.getRuns().get(0);
                JSONObject jsonV = list.getJSONObject(j);
                try {
                    cellParagraphRun.setText(jsonV.getString("text"));
                    if (jsonV.get("var")!=null){
//                        cellParagraphRun.setFontSize();
                        CTRPr pr = cellParagraphRun.getCTR().getRPr();
                        CTHpsMeasure ctSize = pr.isSetSz() ? pr.getSz() : pr.addNewSz();
                        ctSize.setVal(BigInteger.valueOf(21));
                    }
                }catch (Exception e){
                    //pass
                }

            }
        }
    }

//    private void fillFields(XWPFTable table,Integer start ,JSONArray fields,JSONArray tableData) {
//        List<XWPFTableRow> rowList = table.getRows();
//        for(int i = start; i < start + tableData.size(); i++) {
//            JSONArray list = tableData.getJSONArray(i);
//            List<XWPFTableCell> cellList = rowList.get(i).getTableCells();
//            for(int j = 0; j < list.size(); j++) {
//                XWPFParagraph cellParagraph = cellList.get(j).getParagraphArray(0);
//                XWPFRun cellParagraphRun = cellParagraph.getRuns().get(0);
//                JSONObject jsonV = list.getJSONObject(j);
//                try {
//                    cellParagraphRun.setText(jsonV.getString("text"));
//                    if (jsonV.get("var")!=null){
////                        cellParagraphRun.setFontSize();
//                        CTRPr pr = cellParagraphRun.getCTR().getRPr();
//                        CTHpsMeasure ctSize = pr.isSetSz() ? pr.getSz() : pr.addNewSz();
//                        ctSize.setVal(BigInteger.valueOf(21));
//                    }
//                }catch (Exception e){
//                    //pass
//                }
//
//            }
//        }
//    }

    private void createBarChart(JSONObject jsonObject) throws IOException, InvalidFormatException {
        // 2、创建chart图表对象,抛出异常
        XWPFChart chart = document.createChart(5270000, 10 * Units.EMU_PER_CENTIMETER);
//        XWPFChart chart = document.createChart(10*XDDFChart.DEFAULT_WIDTH,8*XDDFChart.DEFAULT_HEIGHT);

        // 3、图表相关设置
        chart.setTitleText(jsonObject.getString("titleText")); // 图表标题
        chart.setTitleOverlay(false); // 图例是否覆盖标题

        // 4、图例设置
        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.TOP); // 图例位置:上下左右

        XDDFCategoryAxis xAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); // 创建X轴,并且指定位置
        xAxis.setTitle(jsonObject.getString("xAxis")); // x轴标题

        XDDFValueAxis yAxis = chart.createValueAxis(AxisPosition.LEFT); // 创建Y轴,指定位置
        yAxis.setTitle(jsonObject.getString("yAxis")); // Y轴标题

        ChartTypes chartTypes = ChartTypes.BAR;

        // 7、创建柱状图对象
        XDDFBarChartData barChart = (XDDFBarChartData) chart.createData(chartTypes, xAxis, yAxis);
        barChart.setBarDirection(BarDirection.COL); // 设置柱状图的方向:BAR横向,COL竖向,默认是BAR

        // 5、X轴(分类轴)相关设置
        JSONArray xDatas = jsonObject.getJSONArray("xAxisData");
        ArrayList<String> xAxisData = null;
        xDatas.forEach( data -> {
            xAxisData.add(data.toString());
        });
        String[] x = (String[]) xAxisData.toArray();

        XDDFCategoryDataSource xAxisSource = XDDFDataSourcesFactory.fromArray(x); // 设置X轴数据

        // 6、Y轴(值轴)相关设置

        yAxis.setCrossBetween(AxisCrossBetween.BETWEEN); // 设置图柱的位置:BETWEEN居中

        JSONArray yDatas = jsonObject.getJSONArray("yAxisData");
        JSONArray barSeries = jsonObject.getJSONArray("barSeries");

        for (int i = 0;i<yDatas.size();i++){
            ArrayList<Integer> yAxisData = null;
            JSONArray datas = yDatas.getJSONArray(i);
            for (int j = 0;j<datas.size();j++){
                yAxisData.add(datas.getInteger(j));
            }
            Integer[] y = (Integer[]) xAxisData.toArray();
            XDDFNumericalDataSource<Integer> yAxisSource = XDDFDataSourcesFactory.fromArray(y); // 设置Y轴数据
            // 8、加载柱状图数据集
            XDDFBarChartData.Series bar = (XDDFBarChartData.Series) barChart.addSeries(xAxisSource, yAxisSource);
            try {
                bar.setTitle(barSeries.getString(i), null); // 图例标题
            }catch (Exception e){
                //pass
                throw new InvalidFormatException("barSeries数组长度需与yAxisData一致");
            }
        }



        // 9、绘制柱状图
        chart.plot(barChart);
    }

    public void documentEditor(JSONArray jsonArray){
        BigInteger numId = createNumbering();
        jsonArray.forEach(obj ->{
            JSONObject jsonObject = JSONObject.parseObject(obj.toString());
            String type = jsonObject.getString("type");
            switch (type){
                case "title":
                    createTitleParagraph(jsonObject,numId);
                    break;
                case "table":
                    createTable(jsonObject);
                    break;
                case "content":
                    createCommonParagraph(jsonObject,numId);
                    break;
                case "tip":
                    createTip(jsonObject,numId);
                    break;
                case "chart":
                    try {
                        if ("BAR".equals(jsonObject.getString("chartTypes"))){
                            createBarChart(jsonObject);
                        }
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                    break;

            }
            try {
                if (jsonObject.getJSONArray("children").size()>0){
                    documentEditor(jsonObject.getJSONArray("children"));
                }
            }catch (Exception e){
//                e.printStackTrace();
            }
        });
    }

    public XWPFDocument getDocument(){
        return document;
    }

    public void saveDocument(String savePath){
        try {
            xwpfHelper.saveDocument(document,savePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
